{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2f96340f",
   "metadata": {},
   "outputs": [],
   "source": [
    "pip install backtrader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39f920a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "import backtrader as bt\n",
    "import os\n",
    "import sys\n",
    "import datetime"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39633aef",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "458a2e8b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "启动资金: 2000000.00\n",
      "2020-04-22, 买入, 7898.31\n",
      "2021-03-04, 卖出, 15797.40\n",
      "2021-03-05, 交易中，毛利1508288.70, 净利 1484899.78\n",
      "2021-04-22, 买入, 17743.17\n",
      "2021-04-23, 订单取消或被拒绝\n",
      "2021-04-23, 买入, 17954.10\n",
      "2021-04-26, 订单取消或被拒绝\n",
      "2021-04-26, 买入, 17684.46\n",
      "2021-04-27, 订单取消或被拒绝\n",
      "2021-04-27, 买入, 17942.38\n",
      "2021-04-28, 订单取消或被拒绝\n",
      "2021-04-28, 买入, 18420.40\n",
      "2021-04-29, 订单取消或被拒绝\n",
      "2021-04-29, 买入, 18396.80\n",
      "2021-04-30, 订单取消或被拒绝\n",
      "2021-04-30, 买入, 18171.81\n",
      "2021-05-06, 订单取消或被拒绝\n",
      "2021-05-06, 买入, 17589.69\n",
      "2021-05-07, 订单取消或被拒绝\n",
      "2021-05-07, 买入, 17279.09\n",
      "2021-07-07, 卖出, 18952.72\n",
      "2021-07-08, 交易中，毛利363167.10, 净利 327135.66\n",
      "2021-09-29, 买入, 16770.73\n",
      "2022-01-14, 卖出, 16100.74\n",
      "2022-01-17, 交易中，毛利-124480.66, 净利 -157255.51\n",
      "2022-05-18, 买入, 14284.82\n",
      "2022-05-19, 卖出, 14145.36\n",
      "2022-05-20, 交易中，毛利31266.46, 净利 2956.38\n",
      "2022-05-20, 买入, 14743.51\n",
      "2022-08-02, 卖出, 15299.51\n",
      "2022-08-03, 交易中，毛利131288.06, 净利 101207.90\n",
      "2022-12-06, 买入, 14846.00\n",
      "2023-02-10, 最终的账户资产为4161197.55\n"
     ]
    }
   ],
   "source": [
    "\n",
    "class TestStrategy(bt.Strategy):\n",
    "    \"\"\"\n",
    "    构建自己的策略\n",
    "    \"\"\"\n",
    "\n",
    "    def log(self, txt, dt=None, doprint=False):\n",
    "        ''' 日志函数，用于统一输出日志格式 '''\n",
    "        if doprint:\n",
    "            dt = dt or self.datas[0].datetime.date(0)\n",
    "            print('%s, %s' % (dt.isoformat(), txt))\n",
    "\n",
    "    def __init__(self):\n",
    "\n",
    "        # 初始化相关数据\n",
    "        self.dataclose = self.datas[0].close\n",
    "        self.order = None\n",
    "        self.buyprice = None\n",
    "        self.buycomm = None\n",
    "\n",
    "        # 五日移动平均线\n",
    "        self.sma5 = bt.indicators.SimpleMovingAverage(\n",
    "            self.datas[0], period=18)\n",
    "        # 十日移动平均线\n",
    "        self.sma10 = bt.indicators.SimpleMovingAverage(\n",
    "            self.datas[0], period=47)\n",
    "\n",
    "    def notify_order(self, order):\n",
    "        \"\"\"\n",
    "        订单状态处理\n",
    "        Arguments:\n",
    "            order {object} -- 订单状态\n",
    "        \"\"\"\n",
    "        if order.status in [order.Submitted, order.Accepted]:\n",
    "            # 如订单已被处理，则不用做任何事情\n",
    "            return\n",
    "\n",
    "        # 检查订单是否完成\n",
    "        if order.status in [order.Completed]:\n",
    "            if order.isbuy():\n",
    "                self.buyprice = order.executed.price\n",
    "                self.buycomm = order.executed.comm\n",
    "            self.bar_executed = len(self)\n",
    "\n",
    "        # 订单因为缺少资金之类的原因被拒绝执行\n",
    "        elif order.status in [order.Canceled, order.Margin, order.Rejected]:\n",
    "            self.log('订单取消或被拒绝',doprint=True)\n",
    "\n",
    "        # 订单状态处理完成，设为空\n",
    "        self.order = None\n",
    "\n",
    "    def notify_trade(self, trade):\n",
    "        \"\"\"\n",
    "        交易成果\n",
    "        \n",
    "        Arguments:\n",
    "            trade {object} -- 交易状态\n",
    "        \"\"\"\n",
    "        if not trade.isclosed:\n",
    "            return\n",
    "\n",
    "        # 显示交易的毛利率和净利润\n",
    "        self.log('交易中，毛利%.2f, 净利 %.2f' %\n",
    "                 (trade.pnl, trade.pnlcomm), doprint=True)\n",
    "\n",
    "    def next(self):\n",
    "        ''' 下一次执行 '''\n",
    "\n",
    "        # 记录收盘价\n",
    "        self.log('Close, %.2f' % self.dataclose[0])\n",
    "\n",
    "        # 是否正在下单，如果是的话不能提交第二次订单\n",
    "        if self.order:\n",
    "            return\n",
    "\n",
    "        # 是否已经买入\n",
    "        if not self.position:\n",
    "            # 还没买，如果 MA5 > MA10 说明涨势，买入\n",
    "            if self.sma5[0] > self.sma10[0]:\n",
    "                self.log('买入, %.2f' % self.dataclose[0],doprint=True)\n",
    "                self.order = self.buy()\n",
    "        else:\n",
    "            # 已经买了，如果 MA5 < MA10 ，说明跌势，卖出\n",
    "            if self.sma5[0] < self.sma10[0]:\n",
    "                self.log('卖出, %.2f' % self.dataclose[0],doprint=True)\n",
    "                self.order = self.sell()\n",
    "\n",
    "    def stop(self):\n",
    "        self.log(u'最终的账户资产为%.2f' %\n",
    "                 (self.broker.getvalue()), doprint=True)\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "\n",
    "    # 初始化模型\n",
    "    cerebro = bt.Cerebro()\n",
    "\n",
    "    # 构建策略\n",
    "    strats = cerebro.addstrategy(TestStrategy)\n",
    "    # 每次买100股\n",
    "    cerebro.addsizer(bt.sizers.FixedSize, stake=200)\n",
    "\n",
    "    # 加载数据到模型中\n",
    "    data = bt.feeds.GenericCSVData(\n",
    "        dataname='../第一课/history_A_stock_k_data.csv',\n",
    "        fromdate=datetime.datetime(2020, 1, 1),\n",
    "        todate=datetime.datetime(2023, 2, 12),\n",
    "        dtformat='%Y-%m-%d',\n",
    "        datetime=0,\n",
    "        open=2,\n",
    "        high=3,\n",
    "        low=4,\n",
    "        close=5,\n",
    "        volume=7\n",
    "    )\n",
    "    cerebro.adddata(data)\n",
    "\n",
    "    # 设定初始资金和佣金\n",
    "    cerebro.broker.setcash(2000000.0)\n",
    "    cerebro.broker.setcommission(0.005)\n",
    "\n",
    "    # 策略执行前的资金\n",
    "    print('启动资金: %.2f' % cerebro.broker.getvalue())\n",
    "\n",
    "    # 策略执行\n",
    "    cerebro.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bfd8c6cb",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "546bb57b",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18faa05d",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
